#ifndef __QpwWorld__
#define __QpwWorld__

#include <QtCore/QList>
#include <QtCore/QObject>
#include <QpwGeometryDatabase.h>
#include <QpwStyleDatabase.h>
#include <QpwSubTypeDatabase.h>

class b2Body;
class b2World;
namespace QyNet { class AbstractDatagramEncoder; }

namespace QpwPhysics { class StaticObjectData; };

namespace QpwWorld {

class DecorationObject;
class DynamicObject;
class StaticObject;

class AbstractController {
public:
    virtual ~AbstractController() {}

    virtual void advance( qreal elapsedTime ) = 0;

};

class MovingController : public AbstractController {
public:
    explicit MovingController( DynamicObject * dynamicObject = 0 );
    virtual ~MovingController() {}

    qreal direction() const { return p_direction; }
    qreal movingDirection() const { return p_movingDirection; }
    qreal realMovingDirection() const;
    bool isMoving() const { return p_moving; }
    bool isRotation() const { return p_rotation; }
    QpwWorld::DynamicObject * dynamicObject() const { return p_dynamicObject; }
    qreal movingSpeed() const { return p_movingSpeed; }

    void setDirection( qreal direction );
    void setMovingDirection( qreal movingDirection );
    virtual void advance( qreal elapsedTime );
    void beginMoving();
    void endMoving();
    void setDynamicObject( DynamicObject * dynamicObject );
    void setMovingSpeed( qreal movingSpeed );

    qreal rotationSpeed;      // radian per second

private:
    void updateMoving();

    QpwWorld::DynamicObject * p_dynamicObject;
    b2Body * body;
    qreal p_direction,
        p_movingDirection,  // real moving direction = movingDirection + direction
        p_movingSpeed;      // meter per second
    bool p_moving,
        p_rotation;

};

class Processor : public QObject {
    Q_OBJECT
public:
    explicit Processor( QObject * parent = 0 );
    virtual ~Processor();

    b2World * physicWorld() const { return p_physicWorld; }

    QpwWorld::DecorationObject * createObject( const QpwSubType & subtype, const QUuid & uuid = QUuid() );
    void removeObject( QpwWorld::DecorationObject * object );
    bool loadData( const QString & dataPath );
    QMap<QUuid,QpwWorld::DecorationObject*> objects;
    QpwGeometryDatabase geometryDatabase;
    QpwStyleDatabase styleDatabase;
    QpwSubTypeDatabase subTypeDatabase;
    QList<AbstractController*> controllers;

public slots:
    void start( int interval );
    void stop();

private:
    virtual void send( QyNet::AbstractDatagramEncoder * datagram ) { Q_UNUSED(datagram); }
    void timerEvent( QTimerEvent * event );

    b2World * p_physicWorld;
    int p_timerId;
    QList<QpwWorld::DecorationObject*> p_objects;

};

};

#endif//__QpwWorld__
